package com.aifeng.utils

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.content.res.Resources
import android.graphics.Color
import android.graphics.Paint
import android.view.KeyEvent
import android.view.View
import android.widget.Button
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import cn.bingoogolapple.qrcode.zxing.QRCodeEncoder
import com.aifeng.base.*
import com.aifeng.common_ui.base.*
import com.aifeng.common_ui.helper.*
import com.aifeng.common_ui.view.FullyLinearLayoutManager
import com.aifeng.hassan_food.R
import com.aifeng.hassan_food.WebActivity
import com.aifeng.hassan_food.mine.SettingForgetActivity
import com.aifeng.model.AreaData
import com.flyco.dialog.entity.DialogMenuItem
import com.flyco.dialog.widget.ActionSheetDialog
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.jungly.gridpasswordview.GridPasswordView
import com.luck.picture.lib.config.PictureConfig
import com.luck.picture.lib.tools.PictureFileUtils
import com.maning.mndialoglibrary.MProgressDialog
import com.maning.mndialoglibrary.config.MDialogConfig
import com.tuyenmonkey.textdecorator.TextDecorator
import com.tuyenmonkey.textdecorator.callback.OnTextClickListener
import com.weigan.loopview.LoopView
import io.reactivex.Completable
import io.reactivex.Flowable
import me.jessyan.autosize.AutoSizeCompat
import net.idik.lib.slimadapter.SlimAdapter
import org.jetbrains.anko.longToast
import org.jetbrains.anko.startActivity
import org.jetbrains.anko.toast
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList

fun Activity.showLoadingDialog(hint: String = "加载中...") =
    DialogHelper.showDialog(this, hint)

fun Activity.cancelLoadingDialog() = DialogHelper.dismissDialog()

object DialogHelper {

    fun showDialog(context: Context, hint: String = "") {
        dismissDialog()

        MProgressDialog.showProgress(
            context,
            hint,
            MDialogConfig.Builder()
                .isCancelable(true)
                .isCanceledOnTouchOutside(false)
                .build()
        )
    }

    fun dismissDialog() {
        if (MProgressDialog.isShowing())
            MProgressDialog.dismissProgress()
    }

    /**
     * Dialog适配AutoSize
     */
    fun adjustAutoSize(context: Context): Context {
        return object : ContextWrapper(context) {
            override fun getResources(): Resources {
                AutoSizeCompat.autoConvertDensityBaseOnWidth(super.getResources(), 360f)
                // AutoSizeCompat.autoConvertDensityBaseOnHeight(super.getResources(), 640f)
                return super.getResources()
            }
        }
    }

    fun Context.showListDialog(
        vararg params: String,
        listener: (Int, String) -> Unit
    ) {
        ActionSheetDialog(this, params, null).apply {
            isTitleShow(false)
            lvBgColor(getColorEx(R.color.white))
            itemTextColor(getColorEx(R.color.black))
            itemHeight(45f)
            itemTextSize(15f)
            dividerHeight(0.5f)
            dividerColor(getColorEx(R.color.divider))
            cancelText(getColorEx(R.color.light))
            cancelTextSize(15f)
            layoutAnimation(null)
            show()

            setOnOperItemClickL { _, _, index, _ ->
                dismiss()
                listener.invoke(index, params[index])
            }
        }
    }

    fun Context.showListDialog(
        list: ArrayList<DialogMenuItem>,
        listener: (DialogMenuItem) -> Unit
    ) {
        ActionSheetDialog(this, list, null).apply {
            isTitleShow(false)
            lvBgColor(getColorEx(R.color.white))
            itemTextColor(getColorEx(R.color.black))
            itemHeight(45f)
            itemTextSize(15f)
            dividerHeight(0.5f)
            dividerColor(getColorEx(R.color.divider))
            cancelText(getColorEx(R.color.light))
            cancelTextSize(15f)
            layoutAnimation(null)
            show()

            setOnOperItemClickL { _, _, index, _ ->
                dismiss()
                listener.invoke(list[index])
            }
        }
    }

    fun Context.showPayDialog(onFinished: (String) -> Unit) {
        val dialog = object : BottomDialog(this) {
            override fun onCreateView(): View {
                val view = inflate<View>(R.layout.dialog_pay_pwd)
                view.find<GridPasswordView>(R.id.dialog_pwd).apply {
                    setOnChangedListener {
                        onInputFinish {
                            dismiss()
                            postDelayed({ onFinished(it) }, 500)
                        }
                    }

                    postDelayed({ performClick() }, 300)
                }

                view.find<View>(R.id.dialog_back).oneClick { dismiss() }
                view.find<View>(R.id.dialog_forget).oneClick {
                    dismiss()
                    startActivityEx<SettingForgetActivity>()
                }

                return view
            }
        }
        dialog.setCanceledOnTouchOutside(false)
        dialog.show()
    }

    fun Context.showParamDialog(items: List<Pair<String, String>>) {
        val dialog = BottomSheetDialog(this, R.style.BottomSheetDialogStyle)
        val view = inflate<View>(R.layout.dialog_param_list)

        view.find<Button>(R.id.bt_ok).oneClick { dialog.dismiss() }
        view.find<RecyclerView>(R.id.dialog_list).apply {
            isNestedScrollingEnabled = false
            layoutManager = FullyLinearLayoutManager(this@showParamDialog)
            adapter = SlimAdapter.create()
                .register<String>(R.layout.item_param_list) { data, injector ->
                    val inners = data.split(",")
                    injector.text(R.id.item_param_title, inners[0])
                        .text(R.id.item_param_content, inners[1])
                }

            val list = ArrayList<String>()
            items.mapTo(list) { "${it.first},${it.second}" }
            (adapter as SlimAdapter).updateData(list)
        }

        dialog.setContentView(view)
        // 默认展开
        val bottomSheetBehavior = BottomSheetBehavior.from(view.parent as View)
        bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
        dialog.show()
    }

    fun Context.showCarDialog(
        url: String,
        price: String,
        orginPrice: String,
        way: String = "购物车",
        unit: String = "默认",
        type: String = "single",
        hint: String = "加入购物车",
        onResult: (String) -> Unit = {}
    ) {
        val dialog = object : BottomDialog(this) {
            @SuppressLint("SetTextI18n")
            override fun onCreateView(): View {
                val view = inflate<View>(R.layout.dialog_join_car)

                view.find<ImageView>(R.id.dialog_close).oneClick { dismiss() }
                view.find<ImageView>(R.id.dialog_img).loadRoundedImage(url = url)
                view.find<ImageView>(R.id.dialog_set).visibility =
                    if (type == "package") View.VISIBLE else View.GONE
                view.find<TextView>(R.id.dialog_price).apply {
                    text = setHtmlSmall(
                        "¥ ${if (isLogin) price.formatDecimalWhenHave() else orginPrice.formatDecimalWhenHave()}",
                        "¥"
                    )
                }
                view.find<TextView>(R.id.dialog_orgin).apply {
                    paint.flags = Paint.STRIKE_THRU_TEXT_FLAG
                    text = "¥ ${orginPrice.formatDecimalWhenHave()}"
                    visibility = if (isLogin) View.VISIBLE else View.GONE
                }

                view.find<TextView>(R.id.dialog_type).text = "规格：$unit"

                val numText = view.find<TextView>(R.id.dialog_num)
                view.find<ImageView>(R.id.dialog_plus)
                    .oneClick(duration = 300) {
                        if (numText.textString() == "1") {
                            toast("最少购买一件商品！")
                            return@oneClick
                        }

                        numText.text = (numText.textString().toNotInt() - 1).toString()
                    }
                view.find<ImageView>(R.id.dialog_add)
                    .oneClick(duration = 300) {
                        numText.text = (numText.textString().toNotInt() + 1).toString()
                    }

                view.find<Button>(R.id.bt_join).apply {
                    text = hint
                    oneClick {
                        if (way == "下单") {
                            if (type != "package"
                                && numText.textString().toNotInt() < 6
                            ) {
                                toast("非套餐类商品至少购满6件才可下单！")
                                return@oneClick
                            }
                        }

                        dismiss()
                        Completable.timer(300, TimeUnit.MILLISECONDS)
                            .compose(applyCompletableSchedulers())
                            .subscribe {
                                onResult.invoke(numText.textString())
                            }
                    }
                }

                return view
            }
        }

        dialog.setCanceledOnTouchOutside(false)
        dialog.show()
    }

    fun Context.showQRcodeDialog(
        hint: String = "使用微信扫描进入店铺即可下单",
        url: String = "",
        name: String = "",
        code: String = "",
        type: String = "",
        listener: (String) -> Unit = {}
    ) {
        val dialog = object : BaseDialog(this) {

            override fun onCreateView(): View {
                widthScale(0.0f)
                val view = inflate<View>(R.layout.dialog_qrcode_hint)
                val mContainer = view.find<FrameLayout>(R.id.dialog_container)

                view.find<ImageView>(R.id.dialog_close).oneClick { dismiss() }
                view.find<TextView>(R.id.dialog_code).oneClick {
                    if (code.isNotEmpty()) {
                        copyStringToClip(code)
                        toast("已复制邀请码到剪切板！")
                    }
                }

                view.find<TextView>(R.id.dialog_save)
                    .oneClick {
                        Flowable.just(mContainer)
                            .map {
                                return@map BitmapHelper.saveBitmap(
                                    this@showQRcodeDialog,
                                    it.getBitmap(),
                                    PictureFileUtils.createCameraFile(
                                        this@showQRcodeDialog,
                                        PictureConfig.TYPE_IMAGE,
                                        "", "", ""
                                    )!!
                                )
                            }
                            .compose(applyFlowableSchedulers())
                            .subscribeByFinally(
                                onSuccess = { longToast(it) },
                                onFinally = { dismiss() }
                            )
                    }

                return view
            }

            @SuppressLint("SetTextI18n", "CheckResult")
            override fun setUiBeforShow() {
                val img = createView.find<ImageView>(R.id.dialog_img)
                createView.find<TextView>(R.id.dialog_hint).text = hint
                createView.find<TextView>(R.id.dialog_name).text = name
                createView.find<TextView>(R.id.dialog_code).text = "邀请码：${code}"

                if (type == "url") img.loadImage(url)
                else {
                    Flowable.just(url)
                        .map {
                            return@map QRCodeEncoder.syncEncodeQRCode(it, dp2px(150f), Color.BLACK)
                        }
                        .compose(applyFlowableSchedulers())
                        .subscribe { img.setImageBitmap(it) }
                }
            }
        }

        dialog.setCanceledOnTouchOutside(false)
        dialog.show()
    }

    fun Context.showHintDialog(
        title: String = "温馨提示",
        hint: String = "",
        cancel: String = "取消",
        sure: String = "确定",
        isForced: Boolean = false,
        onCancel: () -> Unit = {},
        onSure: () -> Unit = {}
    ) {
        val dialog = object : BaseDialog(this) {

            override fun onCreateView(): View {
                widthScale(0.7f)
                val view = inflate<View>(R.layout.dialog_remind_hint)

                val tvTitle = view.findViewById<TextView>(R.id.dialog_title)
                val tvHint = view.findViewById<TextView>(R.id.dialog_hint)
                val btCancel = view.findViewById<TextView>(R.id.dialog_cancel)
                val btSure = view.findViewById<TextView>(R.id.dialog_sure)

                tvTitle.text = title
                tvHint.text = hint
                btCancel.text = cancel
                btSure.text = sure

                btCancel.oneClick {
                    dismiss()
                    onCancel.invoke()
                }

                btSure.oneClick {
                    dismiss()
                    onSure.invoke()
                }

                return view
            }
        }

        dialog.setOnKeyListener { _, keyCode, _ ->
            if (keyCode == KeyEvent.KEYCODE_BACK) return@setOnKeyListener isForced
            else return@setOnKeyListener false
        }
        dialog.setCanceledOnTouchOutside(!isForced)
        dialog.show()
    }

    fun Context.showFirstDialog(
        onCancel: () -> Unit = {},
        onSure: () -> Unit = {}
    ) {
        val dialog = object : BaseDialog(this) {

            override fun onCreateView(): View {
                widthScale(0.8f)
                val view = inflate<View>(R.layout.dialog_first_hint)

                val tvHint = view.findViewById<TextView>(R.id.dialog_hint)
                val btCancel = view.findViewById<TextView>(R.id.dialog_cancel)
                val btSure = view.findViewById<TextView>(R.id.dialog_sure)

                // 去掉 ClickableSpan 点击后的背景色
                tvHint.highlightColor = getColorEx(R.color.transparent)

                TextDecorator
                    .decorate(
                        tvHint,
                        getString(R.string.hint_first)
                    )
                    .setTextColor(R.color.colorAccent, "《服务协议》", "《隐私政策》")
                    .makeTextClickable(
                        OnTextClickListener { _, text ->
                            when (text) {
                                "《服务协议》" -> startActivity<WebActivity>("title" to "用户协议")
                                "《隐私政策》" -> startActivity<WebActivity>("title" to "隐私政策")
                            }
                        },
                        false,
                        "《服务协议》", "《隐私政策》"
                    )
                    .build()

                btCancel.oneClick {
                    dismiss()
                    onCancel.invoke()
                }

                btSure.oneClick {
                    dismiss()
                    onSure.invoke()
                }

                return view
            }
        }

        dialog.setOnKeyListener { _, keyCode, _ ->
            keyCode == KeyEvent.KEYCODE_BACK
        }
        dialog.setCanceledOnTouchOutside(false)
        dialog.show()
    }

    fun Context.showItemDialog(
        title: String = "请选择",
        index: Int = -1,
        items: List<String>,
        listener: (Int, String) -> Unit = { _, _ -> }
    ) {

        val dialog = object : BottomDialog(this) {

            private lateinit var loopView: LoopView

            override fun onCreateView(): View {
                val view = inflate<View>(R.layout.dialog_select_more)

                val tvTitle = view.findViewById<TextView>(R.id.tv_dialog_select_title)
                val tvCancel = view.findViewById<TextView>(R.id.tv_dialog_select_cancle)
                val tvOk = view.findViewById<TextView>(R.id.tv_dialog_select_ok)

                loopView = view.find(R.id.lv_dialog_select_year)
                view.find<LoopView>(R.id.lv_dialog_select_month).gone()
                view.find<LoopView>(R.id.lv_dialog_select_day).gone()
                view.find<LoopView>(R.id.lv_dialog_select_hour).gone()
                view.find<LoopView>(R.id.lv_dialog_select_minute).gone()

                tvTitle.text = title
                loopView.setTextSize(15f)
                loopView.setDividerColor(getColorEx(R.color.divider))
                loopView.setNotLoop()

                tvCancel.oneClick { dismiss() }

                tvOk.oneClick {
                    dismiss()
                    listener.invoke(loopView.selectedItem, items[loopView.selectedItem])
                }

                return view
            }

            override fun setUiBeforShow() {
                loopView.setItems(items)
                loopView.setInitPosition(if (index < 0) 0 else index)
            }

        }

        dialog.show()
    }

    /**
     * 时间选择器（R.layout.dialog_select_more 布局文件）
     * @param minYearValue    最小年份
     * @param maxYearValue    最大年份
     * @param count           年、月、日、时、分、秒的显示个数
     * @param title           标题
     * @param initYear        默认年
     * @param initMonth       默认月
     * @param initDay         默认日
     * @param initHour        默认时
     * @param initMinute      默认分
     * @param isCurrentDate   是否默认选择当天日期（与默认年、月、日、时、分互斥）
     * @param isBeforeLimited 是否限制选择该年内，当天前的日期
     * @param isAfterLimited  是否限制选择该年内，当天后的日期（前后日期互斥）
     * @param callback        回调接口
     */
    fun Context.showDateDialog(
        minYearValue: Int = 1900,
        maxYearValue: Int = 2100,
        count: Int = 5,
        title: String = "请选择",
        initYear: Int = -1,
        initMonth: Int = -1,
        initDay: Int = -1,
        initHour: Int = -1,
        initMinute: Int = -1,
        isCurrentDate: Boolean = true,
        isBeforeLimited: Boolean = false,
        isAfterLimited: Boolean = false,
        callback: (Int, Int, Int, Int, Int, String) -> Unit = { _, _, _, _, _, _ -> }
    ) {

        val dialog = object : BottomDialog(this) {

            private lateinit var loopYear: LoopView
            private lateinit var loopMonth: LoopView
            private lateinit var loopDay: LoopView
            private lateinit var loopHour: LoopView
            private lateinit var loopMinute: LoopView

            override fun onCreateView(): View {
                val view = inflate<View>(R.layout.dialog_select_more)

                val tvTitle = view.findViewById<TextView>(R.id.tv_dialog_select_title)
                val tvCancel = view.findViewById<TextView>(R.id.tv_dialog_select_cancle)
                val tvOk = view.findViewById<TextView>(R.id.tv_dialog_select_ok)

                loopYear = view.find(R.id.lv_dialog_select_year)
                loopMonth = view.find(R.id.lv_dialog_select_month)
                loopDay = view.find(R.id.lv_dialog_select_day)
                loopHour = view.find(R.id.lv_dialog_select_hour)
                loopMinute = view.find(R.id.lv_dialog_select_minute)

                tvTitle.text = title

                loopYear.setTextSize(15f)
                loopMonth.setTextSize(15f)
                loopDay.setTextSize(15f)
                loopHour.setTextSize(15f)
                loopMinute.setTextSize(15f)

                loopYear.setDividerColor(getColorEx(R.color.divider))
                loopMonth.setDividerColor(getColorEx(R.color.divider))
                loopDay.setDividerColor(getColorEx(R.color.divider))
                loopHour.setDividerColor(getColorEx(R.color.divider))
                loopMinute.setDividerColor(getColorEx(R.color.divider))

                loopYear.setNotLoop()
                loopMonth.setNotLoop()
                loopDay.setNotLoop()
                loopHour.setNotLoop()
                loopMinute.setNotLoop()

                when (count) {
                    1 -> {
                        loopMonth.gone()
                        loopDay.gone()
                        loopHour.gone()
                        loopMinute.gone()
                    }
                    2 -> {
                        loopDay.gone()
                        loopHour.gone()
                        loopMinute.gone()
                    }
                    3 -> {
                        loopHour.gone()
                        loopMinute.gone()
                    }
                    4 -> loopMinute.gone()
                }

                tvCancel.oneClick { dismiss() }

                tvOk.oneClick {

                    val year = loopYear.selectedItem + minYearValue
                    var month = loopMonth.selectedItem + 1
                    var day = loopDay.selectedItem + 1
                    val hour = loopHour.selectedItem
                    val minute = loopMinute.selectedItem

                    val calendar = Calendar.getInstance()
                    val yearNow = calendar.get(Calendar.YEAR)
                    val monthNow = calendar.get(Calendar.MONTH)
                    val dayNow = calendar.get(Calendar.DAY_OF_MONTH)

                    var dateNew: String

                    if (isBeforeLimited && year == yearNow) {
                        if (month < monthNow + 1) {
                            month = monthNow + 1
                            day = dayNow
                        }
                        if (month == monthNow + 1 && day < dayNow) day = dayNow
                    }

                    if (isAfterLimited && year == yearNow) {
                        if (month > monthNow + 1) {
                            month = monthNow + 1
                            day = dayNow
                        }
                        if (month == monthNow + 1 && day > dayNow) day = dayNow
                    }

                    when (count) {
                        1 -> dateNew = year.toString() + "年"
                        2 -> {
                            dateNew = if (month < 10) "$year-0$month" else "$year-$month"
                        }
                        3 -> {
                            dateNew = when {
                                month < 10 && day < 10 -> "$year-0$month-0$day"
                                month < 10 && day >= 10 -> "$year-0$month-$day"
                                month >= 10 && day < 10 -> "$year-$month-0$day"
                                else -> "$year-$month-$day"
                            }
                        }
                        4 -> {
                            dateNew = when {
                                month < 10 && day < 10 -> "$year-0$month-0$day ${hour}时"
                                month < 10 && day >= 10 -> "$year-0$month-$day ${hour}时"
                                month >= 10 && day < 10 -> "$year-$month-0$day ${hour}时"
                                else -> "$year-$month-$day ${hour}时"
                            }
                        }
                        else -> {
                            dateNew = when {
                                month < 10 && day < 10 -> "$year-0$month-0$day"
                                month < 10 && day >= 10 -> "$year-0$month-$day"
                                month >= 10 && day < 10 -> "$year-$month-0$day"
                                else -> "$year-$month-$day"
                            }

                            when {
                                hour < 10 && minute < 10 -> dateNew += " 0$hour:0$minute"
                                hour < 10 && minute >= 10 -> dateNew += " 0$hour:$minute"
                                hour >= 10 && minute < 10 -> dateNew += " $hour:0$minute"
                                hour >= 10 && minute >= 10 -> dateNew += " $hour:$minute"
                            }
                        }
                    }

                    dismiss()
                    callback.invoke(year, month, day, hour, minute, dateNew)
                }

                return view
            }

            override fun setUiBeforShow() {
                loopYear.setItems(dateToList(minYearValue, maxYearValue, "%d年"))
                loopMonth.setItems(dateToList(1, 12, "%d月"))
                loopDay.setItems(dateToList(1, 31, "%d日"))
                loopHour.setItems(dateToList(0, 23, "%d时"))
                loopMinute.setItems(dateToList(0, 59, "%d分"))

                if (isCurrentDate) {
                    loopYear.setInitPosition(
                        Calendar.getInstance().get(Calendar.YEAR) - minYearValue
                    )
                    loopMonth.setInitPosition(Calendar.getInstance().get(Calendar.MONTH))
                    loopDay.setInitPosition(Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - 1)
                } else {
                    if (initYear > -1 && initMonth > -1 && initDay > -1 && initHour > -1 && initMinute > -1) {
                        loopYear.setInitPosition(initYear - minYearValue)
                        loopMonth.setInitPosition(initMonth)
                        loopDay.setInitPosition(initDay - 1)
                        loopHour.setInitPosition(initHour)
                        loopMinute.setInitPosition(initMinute)
                    }
                }

                val listBig = listOf(1, 3, 5, 7, 8, 10, 12)
                val listLittle = listOf(4, 6, 9, 11)

                loopMonth.setListener {
                    val monthNum = loopMonth.selectedItem + 1
                    // 判断大小月及是否闰年,用来确定"日"的数据
                    if (monthNum in listBig) {
                        loopDay.setItems(dateToList(1, 31, "%d日"))
                    } else if (monthNum in listLittle) {
                        loopDay.setItems(dateToList(1, 30, "%d日"))
                        if (loopDay.selectedItem == 30) loopDay.setCurrentPosition(29)
                    } else {
                        if ((loopYear.selectedItem + minYearValue) % 4 == 0
                            && (loopYear.selectedItem + minYearValue) % 100 != 0
                            || (loopYear.selectedItem + minYearValue) % 400 == 0
                        ) {
                            loopDay.setItems(dateToList(1, 29, "%d日"))
                            if (loopDay.selectedItem >= 29)
                                loopDay.setCurrentPosition(28)
                        } else {
                            loopDay.setItems(dateToList(1, 28, "%d日"))
                            if (loopDay.selectedItem >= 28)
                                loopDay.setCurrentPosition(27)
                        }
                    }
                }

                loopYear.setListener {
                    val yearNum = loopYear.selectedItem + minYearValue
                    // 判断大小月及是否闰年,用来确定"日"的数据
                    if ((loopMonth.selectedItem + 1) in listBig) {
                        loopDay.setItems(dateToList(1, 31, "%d日"))
                    } else if ((loopMonth.selectedItem + 1) in listLittle) {
                        loopDay.setItems(dateToList(1, 30, "%d日"))
                    } else {
                        if (yearNum % 4 == 0
                            && yearNum % 100 != 0
                            || yearNum % 400 == 0
                        )
                            loopDay.setItems(dateToList(1, 29, "%d日"))
                        else {
                            loopDay.setItems(dateToList(1, 28, "%d日"))
                            if (loopDay.selectedItem == 28)
                                loopDay.setCurrentPosition(27)
                        }
                    }
                }
            }

        }

        dialog.show()
    }

    fun Context.showCityDialog(
        title: String = "请选择",
        list: List<AreaData> = ArrayList(),
        defaultProvince: String = "",
        defaultCity: String = "",
        defaultArea: String = "",
        listener: (String, String, String, String, String, String) -> Unit = { _, _, _, _, _, _ -> }
    ) {
        if (list.isEmpty()) return

        val dialog = object : BottomDialog(this) {

            private lateinit var loopProvince: LoopView
            private lateinit var loopCity: LoopView
            private lateinit var loopArea: LoopView

            override fun onCreateView(): View {
                val view = inflate<View>(R.layout.dialog_select_area)

                val tvTitle = view.findViewById<TextView>(R.id.tv_dialog_select_title)
                val tvCancel = view.findViewById<TextView>(R.id.tv_dialog_select_cancle)
                val tvOk = view.findViewById<TextView>(R.id.tv_dialog_select_ok)

                loopProvince = view.find(R.id.lv_dialog_select_province)
                loopCity = view.find(R.id.lv_dialog_select_city)
                loopArea = view.find(R.id.lv_dialog_select_area)

                tvTitle.text = title

                loopProvince.setTextSize(14f)
                loopCity.setTextSize(14f)
                loopArea.setTextSize(14f)

                loopProvince.setDividerColor(getColorEx(R.color.divider))
                loopCity.setDividerColor(getColorEx(R.color.divider))
                loopArea.setDividerColor(getColorEx(R.color.divider))

                loopProvince.setNotLoop()
                loopCity.setNotLoop()
                loopArea.setNotLoop()

                tvCancel.oneClick { dismiss() }

                tvOk.oneClick {
                    val indexProvince = loopProvince.selectedItem
                    val indexCity = loopCity.selectedItem
                    val indexArea = loopArea.selectedItem

                    val provinceName = list[indexProvince].name
                    val cityName = list[indexProvince].charp[indexCity].name
                    val areaName = list[indexProvince].charp[indexCity].charp[indexArea].name

                    val provinceCode = list[indexProvince].code
                    val cityCode = list[indexProvince].charp[indexCity].code
                    val areaCode = list[indexProvince].charp[indexCity].charp[indexArea].code

                    dismiss()
                    listener.invoke(
                        provinceName,
                        cityName,
                        areaName,
                        provinceCode,
                        cityCode,
                        areaCode
                    )
                }

                return view
            }

            override fun setUiBeforShow() {
                val listProvince = ArrayList<String>()
                val listCity = ArrayList<String>()
                val listArea = ArrayList<String>()

                list.mapTo(listProvince) { it.name }
                if (defaultProvince.isNotEmpty()
                    && defaultCity.isNotEmpty()
                    && defaultArea.isNotEmpty()
                ) {
                    var index = listProvince.indexOf(defaultProvince)
                    val indexProvince = if (index < 0) 0 else index

                    list[indexProvince].charp.mapTo(listCity) { it.name }
                    index = listCity.indexOf(defaultCity)
                    val indexCity = if (index < 0) 0 else index

                    list[indexProvince].charp[indexCity].charp.mapTo(listArea) { it.name }
                    index = listArea.indexOf(defaultArea)
                    val indexArea = if (index < 0) 0 else index

                    loopProvince.setItems(listProvince)
                    loopCity.setItems(listCity)
                    loopArea.setItems(listArea)

                    loopProvince.setInitPosition(indexProvince)
                    loopCity.setInitPosition(indexCity)
                    loopArea.setInitPosition(indexArea)
                } else {
                    list[0].charp.mapTo(listCity) { it.name }
                    list[0].charp[0].charp.mapTo(listArea) { it.name }

                    loopProvince.setItems(listProvince)
                    loopCity.setItems(listCity)
                    loopArea.setItems(listArea)
                }

                loopCity.setListener {
                    val index1 = loopProvince.selectedItem
                    val index2 = loopCity.selectedItem

                    listArea.clear()
                    list[index1].charp[index2].charp.mapTo(listArea) { it.name }

                    loopArea.setItems(listArea)

                    loopArea.setCurrentPosition(0)
                }

                loopProvince.setListener {
                    val index = loopProvince.selectedItem

                    listCity.clear()
                    listArea.clear()

                    list[index].charp.mapTo(listCity) { it.name }
                    list[index].charp[0].charp.mapTo(listArea) { it.name }

                    loopCity.setItems(listCity)
                    loopArea.setItems(listArea)

                    loopCity.setCurrentPosition(0)
                    loopArea.setCurrentPosition(0)
                }
            }

        }

        dialog.show()
    }

    private fun dateToList(minValue: Int, maxValue: Int, format: String?): List<String> {
        val items = ArrayList<String>()
        for (i in 0 until maxValue - minValue + 1) {
            val value = minValue + i
            items.add(if (format != null) String.format(format, value) else value.toString())
        }
        return items
    }

}